package designPattern;

import org.junit.Test;

import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.*;

/***
 * Singleton(单例模式)Java开发中常用的设计模式之一
 * 饿汉式于懒汉式单例模式的6种方式
 */
public class SingletonDemo {
    @Test
    public void testSingletonOne() {
        SingletonOne singletonOne = SingletonOne.INSTANCE;
        System.out.println(singletonOne);
    }

    @Test
    public void testSingletonTwo() {
        SingletonTwo singletonTwo = SingletonTwo.INSTANCE;
        System.out.println(singletonTwo);//返回对象的名字
    }

    @Test
    public void testSingletonThree() {
        SingletonThree singletonThree = SingletonThree.INSTANCE;
        System.out.println(singletonThree);
    }

    @Test
    public void testSingletonFour() throws ExecutionException, InterruptedException {
        SingletonFour singletonFour1 = SingletonFour.getInstance();
        SingletonFour singletonFour2 = SingletonFour.getInstance();
        System.out.println(singletonFour1 == singletonFour2);//返回true

        Callable<SingletonFour> c = new Callable<SingletonFour>() {
            @Override
            public SingletonFour call() throws Exception {
                return SingletonFour.getInstance();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(3);
        Future<SingletonFour> f1 = es.submit(c);
        Future<SingletonFour> f2 = es.submit(c);
        Future<SingletonFour> f3 = es.submit(c);

        SingletonFour s1 = f1.get();
        SingletonFour s2 = f2.get();
        SingletonFour s3 = f3.get();

        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s2 == s3);

        es.shutdown();

    }

    @Test
    public void testSingletonFive() throws ExecutionException, InterruptedException {
        SingletonFive singletonFive1 = SingletonFive.getInstance();
        SingletonFive singletonFive2 = SingletonFive.getInstance();
        System.out.println(singletonFive1 == singletonFive2);//返回true

        Callable<SingletonFive> c = new Callable<SingletonFive>() {
            @Override
            public SingletonFive call() throws Exception {
                return SingletonFive.getInstance();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(3);
        Future<SingletonFive> f1 = es.submit(c);
        Future<SingletonFive> f2 = es.submit(c);
        Future<SingletonFive> f3 = es.submit(c);

        SingletonFive s1 = f1.get();
        SingletonFive s2 = f2.get();
        SingletonFive s3 = f3.get();

        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s2 == s3);

        es.shutdown();

    }

    @Test
    public void testSix(){
        SingletonSix singletonSix1 = SingletonSix.getInstance();
        SingletonSix singletonSix2 = SingletonSix.getInstance();
        System.out.println(singletonSix1 == singletonSix2); //true
    }
}

/**
 * 饿汉式1：直接创建实例对象，不管是否需要这个对象,都会创建对象
 * 1.构造器私有化
 * 2.自行创建
 * 3.对外提供这个实例
 * 4.强调这是一个单例，使用final修饰
 */
class SingletonOne {
    public static final SingletonOne INSTANCE = new SingletonOne();

    private SingletonOne() {
    }
}

/**
 * 饿汉式2：枚举法
 * 表示该类型的对象是有限的几个，这里我们限定为一个，就成为了单例
 */
enum SingletonTwo {
    INSTANCE
}

/**
 * 饿汉式3：静态代码块方式
 * 使用场景：
 * 比如我在私有的构造其中有一个参数，这个参数的值不是固定的,可以随时修改，如值是在资源文件中配置的
 */
class SingletonThree {
    //1.静态代码快创建实例
   /* public static final SingletonThree INSTANCE;
    private SingletonThree(){}
    static {
        INSTANCE = new SingletonThree();
    }*/

    //2.静态代码块使用场景
    public static final SingletonThree INSTANCE;
    private String info;

    static {
        Properties properties = new Properties();
        try {
            properties.load(SingletonThree.class.getClassLoader().getResourceAsStream("designPattern/single.properties"));
            INSTANCE = new SingletonThree(properties.getProperty("info"));
        } catch (IOException e) {
            throw new RuntimeException(e);//不处理异常，直接抛出去
        }
    }

    private SingletonThree(String info) {
        this.info = info;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "SingletonThree{" +
                "info='" + info + '\'' +
                '}';
    }
}

/**
 * 懒汉式1 ：非线程安全的(适用于单线程)
 * 1.构造器私有化
 * 2.用一个私有的静态变量保存这个唯一的实例
 * 3.提供一个静态方法，获取这个实例对象
 */

class SingletonFour {
    private static SingletonFour instance;

    private SingletonFour() {
    }

    public static SingletonFour getInstance() {
        if (instance == null) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new SingletonFour();
        }
        return instance;
    }
}

/**
 * 懒汉式2 ：线程安全的(适用于多线程)，使用同步代码块同步机制解决SingletonFour的线程安全问题
 */
class SingletonFive {
    private static SingletonFive instance;

    private SingletonFive() {
    }

    public static SingletonFive getInstance() {
        if (instance == null) {
            synchronized (SingletonFive.class) {
                if (instance == null) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new SingletonFive();
                }
            }
        }
        return instance;
    }
}

/**
 * 懒汉式3:静态内部类形式,线程安全的(适用于多线程)
 * 在内部类加载和初始化的时候才创建INSTANCE对象
 * 静态内部类不会自动随着外部类的加载和初始化而初始化，它是要单独去加载和初始化的(也就是SingletonSix.getInstance()时后才)
 * 因为实在内部类加载和初始化创建的，因此时线程安全的。代码相比SingletonFive代码更简洁
 */
class SingletonSix{
    private static SingletonSix instance;
    private SingletonSix(){}

    private static class Inner{
        private static final SingletonSix INSTANCE = new SingletonSix();
    }

    public static SingletonSix getInstance(){
        return Inner.INSTANCE;
    }
}